package main

import "fmt"

/**
slice（切片）
- 由下标方括号出来的（如arr[:]）这些出来的都叫slice
- slice不是一个值类型，当然go语言所有类型都是值类型，slice的肚子里面它是有一个数据结构的，文档中说slice是对array的一个view，它是一个视图，如arr[2:6]它是看这个arr的一个2~6的视图
- []int，未标识数组的长度，它就是一个slice
- slice不需要用到指针，slice是底层数组全部的一个景象，改变显示的“视图“，就会直接改变底层数组的数值
*/
func updateSlice(s []int) {
	s[0] = 100
}

// 回看之前3-1的代码，使用slice可以改写使用指针改变原数组的方式
func updateArray3(arr []int) {
	arr[0] = 100
}

func main() {
	/**
	切片的:操作表示半开区间的取值
	*/
	// arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
	//s := arr[2:6]  // 在数学里面相当于取第[2,6)位置的所有元素，切片中的数字表示索引位置
	//fmt.Println(s) // [2,3,4,5]

	/**
	fmt.Println("arr[2:6]=", arr[2:6])
	fmt.Println("arr[:6]=", arr[:6])
	fmt.Println("arr[2:]=", arr[2:])
	fmt.Println("arr[:]=", arr[:]) // 相当于查看完整的一个数组
	*/

	// 以下代码证明了slice是array的一个view层，view层对应发生改变，会影响到原生的array
	/**
	s1 := arr[2:]
	s2 := arr[:]
	fmt.Println("s1=", s1)
	fmt.Println("s2=", s2)
	fmt.Println("updateSlice了s1之后")
	updateSlice(s1)
	fmt.Println(s1)
	fmt.Println(arr)
	fmt.Println("updateSlice了s1之后")
	updateSlice(s2)
	fmt.Println(s2)
	fmt.Println(arr)
	*/
	//updateArray3(arr) // 这样写会报错，array不是slice类型，所以如果数组要转成slice做入参
	/*
		updateArray3(arr[:]) // 加个[:]就可以转成slice
		fmt.Println(arr)
	*/

	/*
		s2 := arr[:]
		s2 = s2[:5]
		s2 = s2[2:]
		s3 := arr[:][:5][2:] // 数组slice一次后变为了slice类型，而slice类型自身可以一直不停的slice下去，得到的依然是一个slice
		fmt.Println(s2)
		fmt.Println(s3)
	*/

	/**
	总结一：
	- slice本身没有数据，是对底层array的一个view
	- 改变slice，会改变底层数组的对应的值
	- slice视图本身可以reslice（即再用[?:?]从中取值）
	*/

	/**
	slice的扩展
	*/
	/*
		arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
		s1 := arr[2:6]
		s2 := s1[3:5]
		fmt.Println("s1=", s1) // [2 3 4 5]
		fmt.Println("s2=", s2) // [5 6]，这个s2的slice，view为：s1[3],s1[4],但是s1是没有下标4的，如果打印s1[4]会报错，但是使用slice从s1视图取值[4]找不到，但是知道s1是从arr视图来的，所以继续往s1继续的下个下标的arr[5]值，所以说slice是可以扩展的
	*/
	/*
		arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
		s1 := arr[2:6]
		s2 := s1[3:6]
		fmt.Println(s2) // s2看s1，看不到s1后面的索引，会看s1看的底层arr
		fmt.Println(s1[3:7]) // 如果看arr都取不到，那么就会报错
	*/

	/**
	slice的底层实现，里面装了ptr、len、cap三个变量
	- ptr：指的是slice开头的那个元素在哪
	- len：说明我这个slice长度是多少，我用方括号[:]取值的时候，只能取到len长度内的值，如果我超过len或者说>=len它都会报下标越界的错
	- cap：代表了我整个arr的从ptr到结束的整个长度，所以上面说到的slice的扩展，只要不超过这个cap，都能进行slice扩展

	额外说明：
	- 关于cap，slice可以向后扩展，但是不能向前扩展
	- s[i]不可以超过len(s)，向后扩展不可以超过底层数组cap(s)
	*/

	arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
	s1 := arr[2:6] // [2,3,4,5]
	s2 := s1[3:5]  // [5,6]
	fmt.Printf("s1=%v，len(s1)=%d，cap(s1)=%d\n", s1, len(s1), cap(s1))
	fmt.Printf("s2=%v，len(s2)=%d，cap(s2)=%d\n", s2, len(s2), cap(s2))
}
